/*
 * Copyright (C) 2018 Hisilicon Limited.
 *
 * this program is for pcie ap dma comm
 *
 * This program is free software; you can redistribute it and /or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version
 */

#ifndef _DMA_COMM_DRV_H_
#define _DMA_COMM_DRV_H_

#ifdef CONFIG_DEBUG_BUGVERBOSE
#undef CONFIG_DEBUG_BUGVERBOSE
#endif

#include <linux/sched.h>
#include <asm/io.h>
#include "drv_log.h"

#define module_devdrv "drv_pcie"
#define devdrv_err(fmt, ...)                                                                                  \
    do {                                                                                                      \
        drv_err(module_devdrv, "<%s:%d:%d> " fmt, current->comm, current->tgid, current->pid, ##__VA_ARGS__); \
    } while (0);
#define devdrv_warn(fmt, ...)                                                                                     \
    do {                                                                                                          \
        drv_warn(module_devdrv, "<%s:%d:%d> " fmt, current->comm, current->tgid, current->pid, ##__VA_ARGS__); \
    } while (0);
#define devdrv_info(fmt, ...)                                                                                  \
    do {                                                                                                       \
        drv_info(module_devdrv, "<%s:%d:%d> " fmt, current->comm, current->tgid, current->pid, ##__VA_ARGS__); \
    } while (0);
#ifdef DRV_PCIE_DEBUG
#define devdrv_debug(fmt...) drv_debug(module_devdrv, fmt)
#else
#define devdrv_debug(fmt...)
#endif

#define DEVDRV_DMA_CHAN_OFFSET 0x100

#define DEVDRV_DMA_TIMEOUT 1000000 /* 1s */
#define DEVDRV_DMA_QUEUE_NOT_WORK 0x1

#define DEVDRV_DMA_SML_PKT_DATA_SIZE 32
#define DEVDRV_DMA_SML_PKT_SQ_DESC_NUM 2

/* RO/SO attribute in SQ */
#define DEVDRV_DMA_SQ_ATTR_SO (1 << 0)
#define DEVDRV_DMA_SQ_ATTR_RO (1 << 1)

/* the opcode of SQ descriptor */
enum devdrv_dma_opcode {
    DEVDRV_DMA_SMALL_PACKET = 0x1,
    DEVDRV_DMA_READ = 0x2,
    DEVDRV_DMA_WRITE = 0x3
};

#define DMA_CTRL0_CHAN_EN_OFFSET 0
#define DMA_CTRL0_CHAN_EN_MASK (0x1 << DMA_CTRL0_CHAN_EN_OFFSET)
#define DMA_CTRL0_ERR_ABORT_EN_OFFSET 2
#define DMA_CTRL0_ERR_ABORT_EN_MASK (0x1 << DMA_CTRL0_ERR_ABORT_EN_OFFSET)
#define DMA_CTRL0_PAUSE_OFFSET 4
#define DMA_CTRL0_PAUSE_MASK (0x1 << DMA_CTRL0_PAUSE_OFFSET)
#define DMA_CTRL0_ARB_WAIGHT_OFFSET 8
#define DMA_CTRL0_ARB_WAIGHT_MASK (0xff << DMA_CTRL0_ARB_WAIGHT_OFFSET)
#define DMA_CTRL0_CQSQ_DIR_OFFSET 24
#define DMA_CTRL0_CQSQ_DIR_MASK (0x1 << DMA_CTRL0_CQSQ_DIR_OFFSET)

#define DMA_CTRL1_QUE_RESET_OFFSET 0
#define DMA_CTRL1_QUE_RESET_MASK (0x1 << DMA_CTRL1_QUE_RESET_OFFSET)

#define DMA_CTRL2_PF_NUM_OFFSET 0
#define DMA_CTRL2_PF_NUM_MASK (0x7 << DMA_CTRL2_PF_NUM_OFFSET)

#define DMA_FSM_QUE_STS_OFFSET 0
#define DMA_FSM_QUE_STS_MASK (0xf << DMA_FSM_QUE_STS_OFFSET)
#define DMA_FSM_QUE_WORK_OFFSET 4
#define DMA_FSM_QUE_WORK_MASK (0x1 << DMA_FSM_QUE_WORK_OFFSET)

#define DMA_SQ_HEAD_OFFSET 0
#define DMA_SQ_HEAD_MASK (0xffff << DMA_SQ_HEAD_OFFSET)

#define DMA_CQ_TAIL_OFFSET 0
#define DMA_CQ_TAIL_MASK (0xffff << DMA_CQ_TAIL_OFFSET)

#define DEVDRV_DMA_REG_ALIGN_SIZE 0x40 /* 64B */

/* offset in reg H file, move here. Start */
#define DEVDRV_DMA_QUEUE_SQ_BASE_L 0x0
#define DEVDRV_DMA_QUEUE_SQ_BASE_H 0x4
#define DEVDRV_DMA_QUEUE_SQ_DEPTH 0x8
#define DEVDRV_DMA_QUEUE_SQ_TAIL 0xC
#define DEVDRV_DMA_QUEUE_CQ_BASE_L 0x10
#define DEVDRV_DMA_QUEUE_CQ_BASE_H 0x14
#define DEVDRV_DMA_QUEUE_CQ_DEPTH 0x18
#define DEVDRV_DMA_QUEUE_CQ_HEAD 0x1C
#define DEVDRV_DMA_QUEUE_CTRL0 0x20
#define DEVDRV_DMA_QUEUE_CTRL1 0x24
#define DEVDRV_DMA_QUEUE_FSM_STS 0x30
#define DEVDRV_DMA_QUEUE_SQ_STS 0x34
#define DEVDRV_DMA_QUEUE_CQ_TAIL 0x3C
#define DEVDRV_DMA_QUEUE_INT_STS 0x40
#define DEVDRV_DMA_QUEUE_INT_MSK 0x44
#define DEVDRV_DMA_QUEUE_DESP0 0x50
#define DEVDRV_DMA_QUEUE_DESP1 0x54
#define DEVDRV_DMA_QUEUE_DESP2 0x58
#define DEVDRV_DMA_QUEUE_DESP3 0x5C
#define DEVDRV_DMA_QUEUE_ERR_ADDR_L 0x60
#define DEVDRV_DMA_QUEUE_ERR_ADDR_H 0x64
#define DEVDRV_DMA_QUEUE_SQ_READ_ERR_PTR 0x68
#define DEVDRV_DMA_INIT_SET 0x70
#define DEVDRV_DMA_QUEUE_DESP4 0x74
#define DEVDRV_DMA_QUEUE_DESP5 0x78
#define DEVDRV_DMA_QUEUE_DESP6 0x7C
#define DEVDRV_DMA_QUEUE_DESP7 0x80
#define DEVDRV_DMA_QUEUE_CTRL2 0x9C

/* offset in reg H file, move here. End */

#define AGENTDRV_AP_SDI_AXIM_REG 0x13000

void devdrv_dma_reg_wr(void __iomem *io_base, u32 offset, u32 val);
void devdrv_dma_reg_rd(const void __iomem *io_base, u32 offset, u32 *val);

int devdrv_get_dma_err_chan(void __iomem *io_base, u32 *chan_id);

void devdrv_get_dma_queue_sts(const void __iomem *io_base, u32 *val);

void devdrv_set_dma_sq_tail(void __iomem *io_base, u32 val);
void devdrv_set_dma_cq_head(void __iomem *io_base, u32 val);

int devdrv_dma_ch_cfg_reset(void __iomem *io_base);
void devdrv_dma_ch_cfg_init(void __iomem *io_base, u64 sq_addr, u64 cq_addr, u32 sq_depth, u32 cq_depth, u32 pf_num,
    u32 sqcq_side);
void devdrv_record_dma_dxf_info(void __iomem *io_base, u32 *queue_init_sts);


void devdrv_dma_set_sq_addr_info(struct devdrv_dma_sq_node *sq_desc, u64 src_addr, u64 dst_addr, u32 length);

void devdrv_dma_set_sq_attr(struct devdrv_dma_sq_node *sq_desc, u32 opcode, u32 attr, u32 pf, u32 wd_barrier,
    u32 rd_barrier);

void devdrv_dma_set_sq_irq(struct devdrv_dma_sq_node *sq_desc, u32 rdie, u32 ldie, u32 msi);

bool devdrv_dma_get_cq_valid(struct devdrv_dma_cq_node *cq_desc, u32 rounds);
void devdrv_dma_set_cq_invalid(struct devdrv_dma_cq_node *cq_desc);
u32 devdrv_dma_get_cq_sqhd(struct devdrv_dma_cq_node *cq_desc);
u32 devdrv_dma_get_cq_status(struct devdrv_dma_cq_node *cq_desc);
#endif
